﻿using Fuse8.ContentManagementFramework.Domain;
using Fuse8.ContentManagementFramework.Domain.Commands.CommandParameters;
using Fuse8.ContentManagementFramework.Domain.Special;
using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.DataAccess.SqlDatabase;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Text;
using System.Xml;

namespace Fuse8.ContentManagementFramework.DataAccess.SqlAccess.Mappers
{
    internal class CmsMediaContentDataMapper : BaseSqlEntityDataMapper<CmsMediaContent, int>
    {
        private static BaseSqlEntityDataMapper<CmsMediaContent, int> _based = new BaseSqlEntityDataMapper<CmsMediaContent, int>(new string[] { "EntityMetaInformation", "SiteGroup", "Site", "SiteCategory", "Tags", "LinkedFiles", "MainFile", "Media" });

        private static Dictionary<string, Func<object, IList<SqlParameter>>> _mappersTo = new Dictionary<string, Func<object, IList<SqlParameter>>>();

        static CmsMediaContentDataMapper()
        {
            _mappersTo.Add("cms_sp_MediaContentSelectAll", (p) => _based.MapTo("cms_sp_MediaContentSelectAll", p, false));
            _mappersTo.Add("cms_sp_MediaContentAddMany", MapForAddMany);
            _mappersTo.Add("cms_sp_MediaContentAdd", (p) => _based.MapTo("cms_sp_MediaContentAdd", p, true));
        }

        public CmsMediaContentDataMapper()
            : base()
        { }

        public override CmsMediaContent MapFrom(string sp, SqlDataReader reader)
        {
            //var entity = base.MapFrom(sp, reader);
            var entity = new CmsMediaContent()
                             {
                                 Id = reader.GetInt32(reader.GetOrdinal("Id")),
                                 MediaId = reader.GetInt32(reader.GetOrdinal("MediaId")),
                                 MetaCode = reader.GetString(reader.GetOrdinal("MetaCode")),
                                 Description = !reader.IsDBNull(reader.GetOrdinal("Description"))
                                                ? reader.GetString(reader.GetOrdinal("Description"))
                                                : null,
                                 MediaContentName = reader.GetString(reader.GetOrdinal("MediaContentName")),
                                 SiteId = !reader.IsDBNull(reader.GetOrdinal("SiteId"))
                                              ? reader.GetInt32(reader.GetOrdinal("SiteId"))
                                              : new int?(),
                                 SiteGroupId = !reader.IsDBNull(reader.GetOrdinal("SiteGroupId"))
                                                   ? reader.GetInt32(reader.GetOrdinal("SiteGroupId"))
                                                   : new int?(),
                                 CreatedBy = reader.GetInt32(reader.GetOrdinal("CreatedBy")),
                                 DateCreated = reader.GetDateTime(reader.GetOrdinal("DateCreated")),
                                 LastUpdatedBy = !reader.IsDBNull(reader.GetOrdinal("LastUpdatedBy"))
                                                     ? reader.GetInt32(reader.GetOrdinal("LastUpdatedBy"))
                                                     : new int?(),
                                 DateLastUpdated = !reader.IsDBNull(reader.GetOrdinal("DateLastUpdated"))
                                                       ? reader.GetDateTime(reader.GetOrdinal("DateLastUpdated"))
                                                       : new DateTime?()
                             };

            if (!Convert.IsDBNull(reader["MainFile_Id"]))
            {
                entity.MainFile = new CmsMediaFile()
                                      {
                                          Id = reader.GetInt32(reader.GetOrdinal("MainFile_Id")),
                                          IsPrimary = reader.GetBoolean(reader.GetOrdinal("MainFile_IsPrimary")),
                                          LinkedFileName =
                                              reader.GetString(reader.GetOrdinal("MainFile_LinkedFileName")),
                                          OriginalFileName =
                                              reader.GetString(reader.GetOrdinal("MainFile_OriginalFileName")),
                                          FileSize = reader.GetInt64(reader.GetOrdinal("MainFile_FileSize")),
                                          Height = !reader.IsDBNull(reader.GetOrdinal("MainFile_Height")) ?
                                                reader.GetInt32(reader.GetOrdinal("MainFile_Height")) :
                                                new int?(),
                                          Width = !reader.IsDBNull(reader.GetOrdinal("MainFile_Width")) ?
                                                reader.GetInt32(reader.GetOrdinal("MainFile_Width")) :
                                                new int?(),
                                          MimeTypeId = !reader.IsDBNull(reader.GetOrdinal("MainFile_MimeTypeId"))
                                              ? reader.GetInt32(reader.GetOrdinal("MainFile_MimeTypeId"))
                                              : new int?()
                                      };

                if (!Convert.IsDBNull(reader["MainFile_MimeTypeId"]))
                {
                    entity.MainFile.MimeType = new CmsMimeType()
                                                   {
                                                       Id = reader.GetInt32(reader.GetOrdinal("MainFile_MimeTypeId")),
                                                       MimeTypeName = reader.GetString(reader.GetOrdinal("MainFile_MimeType_MimeTypeName")),
                                                       IsImage = !reader.IsDBNull(reader.GetOrdinal("MainFile_MimeType_IsImage")) && reader.GetBoolean(reader.GetOrdinal("MainFile_MimeType_IsImage")),
                                                       ContentType = reader.GetString(reader.GetOrdinal("MainFile_MimeType_ContentType")),
                                                   };
                }

                if (!Convert.IsDBNull(reader["BlockFromSearchEngines"]))
                {
                    entity.BlockFromSearchEngines = reader.GetBoolean(reader.GetOrdinal("BlockFromSearchEngines"));
                }
            }
            return entity;
        }

        public override IList<SqlParameter> MapTo(string sp, object parameter, bool isForCreate)
        {
            Guard.ArgumentNotEmpty(sp, "sp");
            Guard.ArgumentNotNull(parameter, "parameter");

            return _mappersTo.ContainsKey(sp) ?
                _mappersTo[sp](parameter) :
                base.MapTo(sp, parameter, isForCreate);
        }

        public static IList<SqlParameter> MapForAddMany(object parameter)
        {
            Guard.ArgumentNotNull(parameter, "parameter");

            IList<SqlParameter> result = new List<SqlParameter>();

            var concreteParameter = parameter as CmsMediaContentCreateCommandParameter;
            if (concreteParameter != null)
            {
                result.Add(new SqlParameter("MediaId", concreteParameter.MediaId));
                result.Add(new SqlParameter("ContentXml", CreateContentXml(concreteParameter.MediaContents)));
                result.Add(new SqlParameter("CreatedBy", concreteParameter.CreatedBy));
                result.Add(new SqlParameter("DateCreated", concreteParameter.DateCreated));
            }

            return result;
        }

        private static string CreateContentXml(IEnumerable<CmsAdminMediaContent> mediaContent)
        {
            string result = string.Empty;

            using (MemoryStream stream = new MemoryStream())
            {
                using (XmlTextWriter writer = new XmlTextWriter(stream, Encoding.Unicode))
                {
                    using (StreamReader reader = new StreamReader(writer.BaseStream, Encoding.Unicode))
                    {
                        //<xml>
                        writer.WriteStartDocument();
                        //<MediaContents>
                        writer.WriteStartElement("MediaContents");

                        foreach (var item in mediaContent)
                        {
                            //<MediaContent>
                            writer.WriteStartElement("MediaContent");

                            //<MediaContentName>
                            writer.WriteStartElement("MediaContentName");
                            writer.WriteValue(item.Name);
                            //</MediaContentName>
                            writer.WriteEndElement();

                            //<Description>
                            writer.WriteStartElement("Description");
                            writer.WriteValue(item.Description);
                            //</Description>
                            writer.WriteEndElement();

                            //<MetaCode>
                            writer.WriteStartElement("MetaCode");
                            writer.WriteValue(item.MetaCode);
                            //</MetaCode>
                            writer.WriteEndElement();

                            //<Description>
                            writer.WriteStartElement("BlockFromSearchEngines");
                            writer.WriteValue(item.BlockFromSearchEngines);
                            //</Description>
                            writer.WriteEndElement();

                            //<MediaFiles>
                            writer.WriteStartElement("MediaFiles");
                            //<MediaFile>
                            writer.WriteStartElement("MediaFile");
                            //<MediaFileId>
                            writer.WriteStartElement("MediaFileId");
                            writer.WriteValue(item.FileId);
                            //</MediaFileId>
                            writer.WriteEndElement();
                            //<IsPrimary>
                            writer.WriteStartElement("IsPrimary");
                            writer.WriteValue(true);
                            //</IsPrimary>
                            writer.WriteEndElement();
                            //</MediaFile>
                            writer.WriteEndElement();
                            //</MediaFiles>
                            writer.WriteEndElement();

                            //<MediaTags>
                            writer.WriteStartElement("MediaTags");
                            if (item.Tags != null)
                            {
                                foreach (var mediaTag in item.Tags)
                                {
                                    //<MediaTag>
                                    writer.WriteStartElement("MediaTag");
                                    //<MediaTagId>
                                    writer.WriteStartElement("MediaTagId");
                                    writer.WriteValue(mediaTag);
                                    //</MediaTagId>
                                    writer.WriteEndElement();
                                    //</MediaTag>
                                    writer.WriteEndElement();
                                }
                            }
                            //</MediaTags>
                            writer.WriteEndElement();

                            //</MediaContent>
                            writer.WriteEndElement();
                        }

                        //</MediaContents>
                        writer.WriteEndElement();
                        //</xml>
                        writer.WriteEndDocument();

                        writer.Flush();

                        stream.Position = 0;

                        result = reader.ReadToEnd();
                    }
                }
            }

            return result;
        }
    }
}